<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
    />
    <title>音频可视化播放器</title>
    <style>
      :root {
        /* Neumorphism Color Palette */
        --bg-primary: #e0e5ec;
        --bg-secondary: #f0f4f8;
        --bg-dark: #d1d9e6;
        --text-primary: #2c3e50;
        --text-secondary: #5a6c7d;
        --text-muted: #8b9dc3;
        --accent-primary: #667eea;
        --accent-secondary: #764ba2;
        --success: #4ecdc4;
        --warning: #f7b731;
        --danger: #fc5c65;
        --shadow-light: #ffffff;
        --shadow-dark: #a3b1c6;
        --border-radius: 20px;
        --border-radius-small: 12px;
        --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      }

      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        font-family: 'Inter', 'Segoe UI', Tahoma, sans-serif;
      }

      body {
        background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
        color: var(--text-primary);
        min-height: 100vh;
        padding: 20px;
        overflow-x: hidden;
        animation: pageLoad 1s ease-out;
      }

      @keyframes pageLoad {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .container {
        max-width: 1200px;
        margin: 0 auto;
        display: grid;
        grid-template-columns: 1fr 350px;
        gap: 30px;
        animation: containerFloat 1.2s ease-out 0.3s both;
      }

      @keyframes containerFloat {
        from {
          opacity: 0;
          transform: translateY(30px) scale(0.95);
        }
        to {
          opacity: 1;
          transform: translateY(0) scale(1);
        }
      }

      header {
        grid-column: 1 / -1;
        text-align: center;
        padding: 30px 20px;
        background: var(--bg-primary);
        border-radius: var(--border-radius);
        box-shadow: 
          8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        margin-bottom: 30px;
        animation: headerSlide 1s ease-out 0.5s both;
        position: relative;
        overflow: hidden;
      }

      header::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
        animation: headerShine 3s ease-in-out infinite;
      }

      @keyframes headerSlide {
        from {
          opacity: 0;
          transform: translateY(-20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      @keyframes headerShine {
        0% { left: -100%; }
        50% { left: 100%; }
        100% { left: 100%; }
      }

      h1 {
        font-size: 2.5rem;
        font-weight: 700;
        background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
        margin-bottom: 12px;
        animation: titleGlow 2s ease-in-out infinite alternate;
        text-shadow: 0 0 20px rgba(102, 126, 234, 0.3);
      }

      @keyframes titleGlow {
        from {
          filter: brightness(1);
        }
        to {
          filter: brightness(1.1);
        }
      }

      .subtitle {
        color: var(--text-secondary);
        font-size: 1.1rem;
        font-weight: 500;
        opacity: 0;
        animation: subtitleFade 1s ease-out 0.8s both;
      }

      @keyframes subtitleFade {
        from {
          opacity: 0;
          transform: translateY(10px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      /* 播放器区域 */
      .player-section {
        background: var(--bg-primary);
        border-radius: var(--border-radius);
        padding: 20px;
        box-shadow: 
          inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
        animation: panelSlide 1s ease-out 0.7s both;
        position: relative;
        overflow: hidden;
      }

      .player-section::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, transparent 50%, rgba(0,0,0,0.05) 100%);
        pointer-events: none;
      }

      @keyframes panelSlide {
        from {
          opacity: 0;
          transform: translateX(-30px);
        }
        to {
          opacity: 1;
          transform: translateX(0);
        }
      }

      /* 媒体播放器 */
      .media-player {
        width: 100%;
        height: 300px;
        border-radius: var(--border-radius-small);
        overflow: hidden;
        background: #000;
        box-shadow: 
          8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        transition: var(--transition);
        margin-bottom: 20px;
      }

      .media-player:hover {
        transform: translateY(-2px);
        box-shadow: 
          12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
      }

      #videoPlayer, #audioPlayer {
        width: 100%;
        height: 100%;
        object-fit: contain;
      }

      #audioPlayer {
        background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-size: 1.2rem;
        font-weight: 600;
      }

      /* 可视化模式选择卡片 */
      .visualization-controls {
        display: flex;
        gap: 12px;
        margin: 20px 0;
        padding: 15px;
        background: var(--bg-primary);
        border-radius: var(--border-radius);
        box-shadow: 
          8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        animation: controlsSlide 0.8s ease 0.3s both;
        overflow-x: auto;
        scrollbar-width: none;
      }

      .visualization-controls::-webkit-scrollbar {
        display: none;
      }

      .control-card {
        min-width: 80px;
        padding: 12px 8px;
        background: var(--bg-primary);
        border-radius: var(--border-radius-small);
        cursor: pointer;
        transition: var(--transition);
        text-align: center;
        box-shadow: 
          4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      .control-card::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
        transition: left 0.5s ease;
      }

      .control-card:hover::before {
        left: 100%;
      }

      .control-card:hover {
        transform: translateY(-3px) scale(1.05);
        box-shadow: 
          6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
      }

      .control-card.active {
        background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.1));
        box-shadow: 
          inset 2px 2px 4px rgba(102, 126, 234, 0.3),
          4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
        transform: scale(1.1);
      }

      .card-icon {
        font-size: 1.8rem;
        margin-bottom: 6px;
        animation: iconBounce 2s ease-in-out infinite;
      }

      @keyframes iconBounce {
        0%, 100% { transform: translateY(0) rotate(0deg); }
        25% { transform: translateY(-3px) rotate(5deg); }
        50% { transform: translateY(0) rotate(0deg); }
        75% { transform: translateY(-2px) rotate(-3deg); }
      }

      .card-title {
        font-size: 0.75rem;
        font-weight: 600;
        color: var(--text-secondary);
        transition: var(--transition);
      }

      .control-card.active .card-title {
        color: var(--accent-primary);
      }

      /* 音频可视化器 */
      .visualizer {
        width: 100%;
        height: 250px;
        margin: 20px 0;
        overflow: hidden;
        position: relative;
        background: var(--bg-primary);
        border-radius: var(--border-radius);
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light);
        animation: visualizerAppear 0.6s ease 0.2s both;
      }

      /* 背景动画层 */
      .background-animation {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
        z-index: 1;
        opacity: 0.3;
      }

      /* 可视化模式容器 */
      .visualization-mode {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 2;
      }

      .visualization-mode canvas {
        width: 100%;
        height: 100%;
        border-radius: var(--border-radius);
      }

      @keyframes visualizerAppear {
        from {
          opacity: 0;
          transform: scale(0.9);
        }
        to {
          opacity: 1;
          transform: scale(1);
        }
      }

      .waveform {
        position: absolute;
        bottom: 0;
        left: 0;
        width: 100%;
        height: 100%;
        display: flex;
        align-items: flex-end;
        justify-content: center;
        padding: 15px;
      }

      .bar {
        width: 4px;
        margin: 0 1px;
        background: var(--accent-primary);
        border-radius: 2px;
        box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
        transition: all 0.1s ease;
        min-height: 2px;
      }

      /* 控制按钮 */
      .controls {
        display: flex;
        justify-content: center;
        gap: 15px;
        margin: 20px 0;
        animation: controlsSlide 0.8s ease 0.4s both;
      }

      @keyframes controlsSlide {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .btn {
        background: var(--bg-primary);
        color: var(--text-primary);
        border: none;
        padding: 12px 20px;
        border-radius: var(--border-radius-small);
        cursor: pointer;
        font-weight: 600;
        font-size: 0.9rem;
        transition: var(--transition);
        display: flex;
        align-items: center;
        gap: 8px;
        box-shadow: 
          4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      .btn::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
        transition: left 0.5s ease;
      }

      .btn:hover::before {
        left: 100%;
      }

      .btn:hover {
        transform: translateY(-2px);
        box-shadow: 
          6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
      }

      .btn:active {
        transform: translateY(0);
        box-shadow: 
          inset 2px 2px 4px var(--shadow-dark),
          inset -2px -2px 4px var(--shadow-light);
      }

      .btn-primary {
        background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
        color: white;
      }

      .btn-success {
        color: var(--success);
      }

      .btn-danger {
        color: var(--danger);
      }

      /* 播放列表区域 */
      .playlist-section {
        background: var(--bg-primary);
        border-radius: var(--border-radius);
        padding: 20px;
        box-shadow: 
          8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        display: flex;
        flex-direction: column;
        height: fit-content;
        max-height: 600px;
        animation: panelSlide 1s ease-out 0.9s both;
        position: relative;
        overflow: hidden;
      }

      .playlist-section::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: linear-gradient(135deg, rgba(255,255,255,0.05) 0%, transparent 50%, rgba(0,0,0,0.02) 100%);
        pointer-events: none;
      }

      .playlist-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20px;
        padding-bottom: 15px;
        position: relative;
        z-index: 1;
      }

      .playlist-header::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        height: 2px;
        background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
        border-radius: 1px;
      }

      .playlist-header h2 {
        color: var(--text-primary);
        font-size: 1.4rem;
        font-weight: 600;
        margin: 0;
      }

      .file-input {
        display: none;
      }

      .file-label {
        display: block;
        background: var(--bg-primary);
        color: var(--accent-secondary);
        padding: 12px 20px;
        border-radius: var(--border-radius-small);
        cursor: pointer;
        text-align: center;
        margin-bottom: 15px;
        transition: var(--transition);
        font-weight: 600;
        box-shadow: 
          4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
        position: relative;
        overflow: hidden;
        z-index: 1;
      }

      .file-label::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(90deg, transparent, rgba(118, 75, 162, 0.1), transparent);
        transition: left 0.5s ease;
        z-index: -1;
      }

      .file-label:hover::before {
        left: 100%;
      }

      .file-label:hover {
        transform: translateY(-2px);
        box-shadow: 
          6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
        background: linear-gradient(135deg, rgba(118, 75, 162, 0.05), rgba(118, 75, 162, 0.02));
      }

      /* 播放列表 */
      #playlist {
        list-style: none;
        overflow-y: auto;
        max-height: 400px;
        padding-right: 8px;
        scrollbar-width: thin;
        scrollbar-color: var(--accent-primary) var(--bg-dark);
        position: relative;
        z-index: 1;
      }

      #playlist::-webkit-scrollbar {
        width: 8px;
      }

      #playlist::-webkit-scrollbar-track {
        background: var(--bg-dark);
        border-radius: 4px;
        box-shadow: inset 2px 2px 4px var(--shadow-dark);
      }

      #playlist::-webkit-scrollbar-thumb {
        background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
        border-radius: 4px;
        box-shadow: 0 2px 4px rgba(0,0,0,0.2);
      }

      #playlist li {
        background: var(--bg-primary);
        padding: 15px 18px;
        margin-bottom: 12px;
        border-radius: var(--border-radius-small);
        display: flex;
        align-items: center;
        cursor: pointer;
        transition: var(--transition);
        box-shadow: 
          4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
        position: relative;
        overflow: hidden;
        animation: listItemSlide 0.5s ease-out;
        animation-fill-mode: both;
      }

      @keyframes listItemSlide {
        from {
          opacity: 0;
          transform: translateX(-20px);
        }
        to {
          opacity: 1;
          transform: translateX(0);
        }
      }

      #playlist li::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
        transition: left 0.5s ease;
      }

      #playlist li:hover::before {
        left: 100%;
      }

      #playlist li:hover {
        transform: translateX(8px) translateY(-2px);
        box-shadow: 
          6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
      }

      #playlist li.active {
        background: linear-gradient(135deg, rgba(78, 205, 196, 0.1), rgba(78, 205, 196, 0.05));
        box-shadow: 
          inset 2px 2px 4px rgba(78, 205, 196, 0.2),
          4px 4px 8px var(--shadow-dark),
          -4px -4px 8px var(--shadow-light);
        border-left: 4px solid var(--success);
      }

      #playlist li.active::after {
        content: '';
        position: absolute;
        right: 15px;
        top: 50%;
        transform: translateY(-50%);
        width: 8px;
        height: 8px;
        background: var(--success);
        border-radius: 50%;
        animation: activePulse 2s ease-in-out infinite;
      }

      @keyframes activePulse {
        0%, 100% {
          opacity: 1;
          transform: translateY(-50%) scale(1);
        }
        50% {
          opacity: 0.6;
          transform: translateY(-50%) scale(1.2);
        }
      }

      .media-info {
        flex-grow: 1;
        overflow: hidden;
        margin-right: 15px;
        position: relative;
        z-index: 1;
      }

      .media-info .title {
        font-weight: 600;
        font-size: 0.95rem;
        color: var(--text-primary);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        margin-bottom: 6px;
        transition: var(--transition);
      }

      #playlist li:hover .media-info .title {
        color: var(--accent-primary);
      }

      .media-info .type {
        font-size: 0.8rem;
        color: var(--text-muted);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        transition: var(--transition);
      }

      .format-tag {
        background: var(--bg-dark);
        color: var(--accent-primary);
        font-size: 0.75rem;
        font-weight: 600;
        padding: 4px 10px;
        border-radius: 12px;
        box-shadow: 
          inset 2px 2px 4px var(--shadow-dark),
          inset -2px -2px 4px var(--shadow-light);
        transition: var(--transition);
        position: relative;
        z-index: 1;
      }

      .format-tag.video {
        color: var(--danger);
        background: linear-gradient(135deg, rgba(252, 92, 101, 0.1), rgba(252, 92, 101, 0.05));
      }

      .format-tag.audio {
        color: var(--success);
        background: linear-gradient(135deg, rgba(78, 205, 196, 0.1), rgba(78, 205, 196, 0.05));
      }

      /* 状态指示器 */
      .status-indicator {
        display: flex;
        align-items: center;
        margin-top: 15px;
        padding: 10px 15px;
        background: var(--bg-dark);
        border-radius: var(--border-radius-small);
        font-size: 0.9rem;
        font-weight: 500;
        color: var(--text-secondary);
        box-shadow: 
          inset 2px 2px 4px var(--shadow-dark),
          inset -2px -2px 4px var(--shadow-light);
        position: relative;
        z-index: 1;
      }

      .status-dot {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        margin-right: 10px;
        background: var(--text-muted);
        transition: var(--transition);
      }

      .status-dot.playing {
        background: linear-gradient(135deg, var(--success), rgba(78, 205, 196, 0.8));
        animation: statusGlow 2s ease-in-out infinite alternate;
      }

      .status-dot.paused {
        background: linear-gradient(135deg, var(--warning), rgba(247, 183, 49, 0.8));
      }

      .status-dot.error {
        background: linear-gradient(135deg, var(--danger), rgba(252, 92, 101, 0.8));
        animation: statusShake 0.5s ease-in-out;
      }

      @keyframes statusGlow {
        from {
          box-shadow: 0 2px 4px rgba(0,0,0,0.2), 0 0 8px rgba(78, 205, 196, 0.3);
        }
        to {
          box-shadow: 0 2px 4px rgba(0,0,0,0.2), 0 0 16px rgba(78, 205, 196, 0.6);
        }
      }

      @keyframes statusShake {
        0%, 100% { transform: translateX(0); }
        25% { transform: translateX(-2px); }
        75% { transform: translateX(2px); }
      }

      /* 响应式设计 */
      @media (max-width: 900px) {
        .container {
          grid-template-columns: 1fr;
          gap: 20px;
        }
        .media-player {
          height: 250px;
        }
        .visualizer {
          height: 150px;
        }
      }

      @media (max-width: 500px) {
        body {
          padding: 15px;
        }
        .media-player {
          height: 200px;
        }
        .visualizer {
          height: 120px;
        }
        .controls {
          flex-direction: column;
          align-items: center;
        }
        .btn {
          width: 100%;
          max-width: 200px;
        }
      }

      /* 暗色模式支持 */
      @media (prefers-color-scheme: dark) {
        :root {
          --bg-primary: #2d3748;
          --bg-secondary: #1a202c;
          --bg-dark: #4a5568;
          --shadow-light: #4a5568;
          --shadow-dark: #1a202c;
          --text-primary: #f7fafc;
          --text-secondary: #a0aec0;
          --text-muted: #718096;
        }
      }

      /* 卡通风格额外动画效果 */
      .bar {
        animation: barFloat 3s ease-in-out infinite;
      }
      
      @keyframes barFloat {
        0%, 100% { transform: translateY(0) scaleX(1); }
        50% { transform: translateY(-2px) scaleX(1.05); }
      }
      
      .control-card:active {
        animation: cardPop 0.2s ease-out;
      }
      
      @keyframes cardPop {
        0% { transform: scale(1.1); }
        50% { transform: scale(0.95); }
        100% { transform: scale(1.1); }
      }
      
      .visualizer::before {
        content: '';
        position: absolute;
        top: -2px;
        left: -2px;
        right: -2px;
        bottom: -2px;
        background: linear-gradient(45deg, 
          rgba(102, 126, 234, 0.3), 
          rgba(118, 75, 162, 0.3), 
          rgba(78, 205, 196, 0.3), 
          rgba(247, 183, 49, 0.3));
        border-radius: var(--border-radius);
        z-index: -1;
        animation: borderGlow 4s ease-in-out infinite;
      }
      
      @keyframes borderGlow {
        0%, 100% { opacity: 0.3; transform: scale(1); }
        50% { opacity: 0.6; transform: scale(1.02); }
      }
      
      .status-indicator {
        animation: statusFloat 2s ease-in-out infinite;
      }
      
      @keyframes statusFloat {
        0%, 100% { transform: translateY(0); }
        50% { transform: translateY(-3px); }
      }
      
      /* 鼠标悬停时的特殊效果 */
      .control-card:hover .card-icon {
        animation: iconWiggle 0.5s ease-in-out;
      }
      
      @keyframes iconWiggle {
        0%, 100% { transform: rotate(0deg) scale(1); }
        25% { transform: rotate(-10deg) scale(1.1); }
        75% { transform: rotate(10deg) scale(1.1); }
      }
      
      /* 播放时的脉冲效果 */
      .status-dot.playing {
        animation: statusGlow 2s ease-in-out infinite alternate, statusPulse 1s ease-in-out infinite;
      }
      
      @keyframes statusPulse {
        0%, 100% { transform: scale(1); }
        50% { transform: scale(1.2); }
      }
      
      /* 跳舞角色样式 */
      .dancing-character {
        position: absolute;
        user-select: none;
        pointer-events: none;
        z-index: 10;
        transition: all 0.1s ease-out;
        filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3));
      }
      
      .dancing-character::before {
         content: '🙌';
         position: absolute;
         top: -10px;
         left: 50%;
         transform: translateX(-50%) rotate(var(--arm-rotation, 0deg));
         font-size: 0.6em;
         opacity: 0.8;
         transition: transform 0.1s ease-out;
       }
       
       .dancing-character::after {
         content: '🦵';
         position: absolute;
         bottom: -15px;
         left: 50%;
         transform: translateX(-50%) rotate(var(--leg-rotation, 0deg));
         font-size: 0.5em;
         opacity: 0.7;
         transition: transform 0.1s ease-out;
       }
      
      @keyframes characterGlow {
        0% { 
          filter: brightness(1) drop-shadow(0 2px 4px rgba(0,0,0,0.3));
          transform: scale(1);
        }
        100% { 
          filter: brightness(1.2) drop-shadow(0 4px 8px rgba(0,0,0,0.5));
          transform: scale(1.05);
        }
      }
      
      @keyframes characterBounce {
        0%, 100% { transform: translateY(0) scale(1); }
        50% { transform: translateY(-10px) scale(1.1); }
      }
      
      @keyframes characterDance {
        0% { transform: rotate(-5deg) scale(1); }
        25% { transform: rotate(5deg) scale(1.1); }
        50% { transform: rotate(-3deg) scale(1); }
        75% { transform: rotate(3deg) scale(1.05); }
        100% { transform: rotate(-5deg) scale(1); }
      }
      
      /* 动画优化 */
      @media (prefers-reduced-motion: reduce) {
        *,
        *::before,
        *::after {
          animation-duration: 0.01ms !important;
          animation-iteration-count: 1 !important;
          transition-duration: 0.01ms !important;
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <header>
        <h1>🎵 音频可视化播放器</h1>
        <p class="subtitle">支持视频/音频播放与实时音频可视化</p>
      </header>

      <!-- 播放器区域 -->
      <section class="player-section">
        <div class="media-player">
          <video id="videoPlayer" controls style="display: none;"></video>
          <audio id="audioPlayer" controls style="display: none;"></audio>
          <div id="placeholderText" style="display: flex; align-items: center; justify-content: center; height: 100%; background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); color: white; font-size: 1.2rem; font-weight: 600;">
            🎵 选择媒体文件开始播放
          </div>
        </div>

        <!-- 可视化模式选择卡片 -->
        <div class="visualization-controls">
          <div class="control-card active" data-mode="bars">
            <div class="card-icon">📊</div>
            <div class="card-title">柱状图</div>
          </div>
          <div class="control-card" data-mode="pie">
            <div class="card-icon">🥧</div>
            <div class="card-title">饼图</div>
          </div>
          <div class="control-card" data-mode="wave">
            <div class="card-icon">🌊</div>
            <div class="card-title">波形图</div>
          </div>
          <div class="control-card" data-mode="particles">
            <div class="card-icon">✨</div>
            <div class="card-title">粒子效果</div>
          </div>
          <div class="control-card" data-mode="circular">
            <div class="card-icon">⭕</div>
            <div class="card-title">圆形谱</div>
          </div>
          <div class="control-card" data-mode="background">
            <div class="card-icon">🎭</div>
            <div class="card-title">背景动画</div>
          </div>
        </div>

        <!-- 音频可视化器 -->
        <div class="visualizer">
          <!-- 背景动画层 -->
          <div class="background-animation" id="backgroundAnimation"></div>
          
          <!-- 柱状图模式 -->
          <div class="visualization-mode" id="barsMode">
            <div class="waveform" id="waveform">
              <div style="display: flex; align-items: center; justify-content: center; width: 100%; color: var(--text-muted); font-size: 1rem;">
                🎶 音频可视化将在播放时显示
              </div>
            </div>
          </div>
          
          <!-- 饼图模式 -->
          <div class="visualization-mode" id="pieMode" style="display: none;">
            <canvas id="pieCanvas" width="400" height="200"></canvas>
          </div>
          
          <!-- 波形图模式 -->
          <div class="visualization-mode" id="waveMode" style="display: none;">
            <canvas id="waveCanvas" width="400" height="200"></canvas>
          </div>
          
          <!-- 粒子效果模式 -->
          <div class="visualization-mode" id="particlesMode" style="display: none;">
            <canvas id="particlesCanvas" width="400" height="200"></canvas>
          </div>
          
          <!-- 圆形谱模式 -->
          <div class="visualization-mode" id="circularMode" style="display: none;">
            <canvas id="circularCanvas" width="400" height="200"></canvas>
          </div>
          
          <!-- 背景动画模式 -->
          <div class="visualization-mode" id="backgroundMode" style="display: none;">
            <div style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: var(--text-muted); font-size: 1rem;">
              🎭 背景动画效果将在播放时显示
            </div>
          </div>
        </div>

        <!-- 控制按钮 -->
        <div class="controls">
          <button id="playBtn" class="btn btn-primary">▶️ 播放</button>
          <button id="pauseBtn" class="btn btn-success">⏸️ 暂停</button>
          <button id="stopBtn" class="btn btn-danger">⏹️ 停止</button>
        </div>

        <!-- 状态指示器 -->
        <div class="status-indicator">
          <div class="status-dot" id="statusDot"></div>
          <span id="statusText">就绪</span>
        </div>
      </section>

      <!-- 播放列表区域 -->
      <section class="playlist-section">
        <div class="playlist-header">
          <h2>📁 媒体列表</h2>
          <button class="btn btn-danger" id="clearPlaylist">
            🗑️ 清空
          </button>
        </div>

        <input
          type="file"
          id="fileInput"
          class="file-input"
          multiple
          accept="video/*,audio/*,.mp4,.mp3,.wav,.ogg,.webm,.flv,.avi,.mov"
        />
        <label for="fileInput" class="file-label">
          📁 选择媒体文件
        </label>

        <ul id="playlist"></ul>
      </section>
    </div>

    <script>
      /**
       * 音频可视化播放器
       * 功能特性：
       * 1. 支持音频和视频文件播放
       * 2. 实时音频频谱可视化（80个频率条）
       * 3. 播放列表管理（拖拽上传、格式识别）
       * 4. 暂停/停止时的缓慢归零动画效果
       * 5. 现代Neumorphism UI设计
       * 6. 响应式布局和键盘快捷键支持
       * 7. 内存管理和资源清理
       */
      
      // 全局变量
      let currentMedia = null;      // 当前播放的媒体元素
      let audioContext = null;     // Web Audio API上下文
      let analyser = null;         // 音频分析器节点
      let animationId = null;      // 动画帧ID
      let playlist = [];           // 播放列表数组
      let currentIndex = -1;       // 当前播放索引
      let isPlaying = false;       // 播放状态标志
      let currentVisualizationMode = 'bars';  // 当前可视化模式
      let particles = [];          // 粒子数组
      let backgroundParticles = []; // 背景粒子数组
      let dancingCharacters = [];  // 跳舞角色数组

      // DOM元素
      const videoPlayer = document.getElementById('videoPlayer');
      const audioPlayer = document.getElementById('audioPlayer');
      const placeholderText = document.getElementById('placeholderText');
      const waveform = document.getElementById('waveform');
      const playBtn = document.getElementById('playBtn');
      const pauseBtn = document.getElementById('pauseBtn');
      const stopBtn = document.getElementById('stopBtn');
      const statusDot = document.getElementById('statusDot');
      const statusText = document.getElementById('statusText');
      const fileInput = document.getElementById('fileInput');
      const playlistEl = document.getElementById('playlist');
      const clearPlaylistBtn = document.getElementById('clearPlaylist');
      
      // 可视化相关DOM元素
      const controlCards = document.querySelectorAll('.control-card');
      const visualizationModes = document.querySelectorAll('.visualization-mode');
      const pieCanvas = document.getElementById('pieCanvas');
      const waveCanvas = document.getElementById('waveCanvas');
      const particlesCanvas = document.getElementById('particlesCanvas');
      const circularCanvas = document.getElementById('circularCanvas');
      const backgroundAnimation = document.getElementById('backgroundAnimation');
      
      // Canvas上下文
      let pieCtx, waveCtx, particlesCtx, circularCtx;

      /**
       * 初始化音频可视化系统
       * 创建Web Audio API上下文，设置音频分析器，连接音频源
       * @param {HTMLMediaElement} mediaElement - 音频或视频元素
       */
      function initAudioContext(mediaElement) {
        try {
          // 关闭现有的音频上下文
          if (audioContext) {
            audioContext.close();
          }
          
          // 创建新的音频上下文和分析器
          audioContext = new (window.AudioContext || window.webkitAudioContext)();
          analyser = audioContext.createAnalyser();
          const source = audioContext.createMediaElementSource(mediaElement);
          
          // 连接音频节点：媒体源 -> 分析器 -> 输出
          source.connect(analyser);
          analyser.connect(audioContext.destination);
          
          // 设置FFT大小为256，提供128个频率数据点
          analyser.fftSize = 256;
          
          // 创建可视化条
          createVisualizerBars();
          
          // 开始可视化动画
          startVisualization();
          
          updateStatus('音频可视化已启动', 'playing');
        } catch (error) {
          console.error('音频上下文初始化失败:', error);
          updateStatus('音频可视化初始化失败', 'error');
        }
      }

      /**
       * 创建音频可视化频率条
       * 动态生成80个频率条元素，根据容器宽度自适应
       */
      function createVisualizerBars() {
        waveform.innerHTML = '';
        const bars = 80;  // 频率条数量
        const barWidth = (waveform.offsetWidth - bars * 2) / bars;  // 计算每个条的宽度
        
        // 创建频率条元素
        for (let i = 0; i < bars; i++) {
          const bar = document.createElement('div');
          bar.className = 'bar';
          bar.style.width = barWidth + 'px';
          bar.style.height = '2px';  // 初始最小高度
          waveform.appendChild(bar);
        }
      }

      // 初始化Canvas上下文
      function initCanvases() {
        // 获取Canvas上下文
        if (pieCanvas) {
          pieCtx = pieCanvas.getContext('2d');
          pieCanvas.width = 400;
          pieCanvas.height = 250;
        }
        if (waveCanvas) {
          waveCtx = waveCanvas.getContext('2d');
          waveCanvas.width = 400;
          waveCanvas.height = 250;
        }
        if (particlesCanvas) {
          particlesCtx = particlesCanvas.getContext('2d');
          particlesCanvas.width = 400;
          particlesCanvas.height = 250;
        }
        if (circularCanvas) {
          circularCtx = circularCanvas.getContext('2d');
          circularCanvas.width = 400;
          circularCanvas.height = 250;
        }
        
        // 设置Canvas样式
        const canvases = [pieCanvas, waveCanvas, particlesCanvas, circularCanvas];
        canvases.forEach(canvas => {
          if (canvas) {
            canvas.style.width = '100%';
            canvas.style.height = '100%';
            canvas.style.display = 'block';
          }
        });
        
        // 初始化粒子
        initParticles();
        initBackgroundParticles();
        initDancingCharacters();
      }
      
      // 切换可视化模式
      function switchVisualizationMode(mode) {
        // 清空所有可视化内容
        clearAllVisualizations();
        
        currentVisualizationMode = mode;
        
        // 更新控制卡片状态
        controlCards.forEach(card => {
          card.classList.remove('active');
          if (card.dataset.mode === mode) {
            card.classList.add('active');
          }
        });
        
        // 切换显示的可视化模式
        visualizationModes.forEach(modeEl => {
          modeEl.style.display = 'none';
        });
        
        const targetMode = document.getElementById(mode + 'Mode');
        if (targetMode) {
          targetMode.style.display = 'block';
        }
        
        // 如果正在播放，重新开始可视化
        if (isPlaying && analyser) {
          startVisualization();
        }
      }
      
      // 清空所有可视化内容
      function clearAllVisualizations() {
        // 清空柱状图
        const bars = waveform.querySelectorAll('.bar');
        bars.forEach(bar => {
          bar.style.height = '2px';
          bar.style.background = 'var(--accent-primary)';
          bar.style.boxShadow = '0 2px 8px rgba(102, 126, 234, 0.3)';
        });
        
        // 清空所有Canvas
        if (pieCtx) pieCtx.clearRect(0, 0, pieCanvas.width, pieCanvas.height);
        if (waveCtx) waveCtx.clearRect(0, 0, waveCanvas.width, waveCanvas.height);
        if (particlesCtx) particlesCtx.clearRect(0, 0, particlesCanvas.width, particlesCanvas.height);
        if (circularCtx) circularCtx.clearRect(0, 0, circularCanvas.width, circularCanvas.height);
        
        // 清空背景动画
        if (backgroundAnimation) {
          backgroundAnimation.style.background = '';
          backgroundAnimation.style.transform = '';
          backgroundAnimation.innerHTML = '';
        }
      }
      
      // 开始可视化动画
      function startVisualization() {
        if (!analyser) return;
        
        // 如果已有动画在运行，先停止
        if (animationId) {
          cancelAnimationFrame(animationId);
        }
        
        const bufferLength = analyser.frequencyBinCount;
        const dataArray = new Uint8Array(bufferLength);
        
        function animate() {
          if (!isPlaying || !analyser) {
            // 如果不在播放状态，停止动画但不触发归零（避免重复调用）
            animationId = null;
            return;
          }
          
          analyser.getByteFrequencyData(dataArray);
          
          // 只渲染当前选中的可视化模式
          switch(currentVisualizationMode) {
            case 'bars':
              renderBarsVisualization(dataArray);
              break;
            case 'pie':
              renderPieVisualization(dataArray);
              break;
            case 'wave':
              renderWaveVisualization(dataArray);
              break;
            case 'particles':
              renderParticlesVisualization(dataArray);
              break;
            case 'circular':
              renderCircularVisualization(dataArray);
              break;
          }
          
          // 只在选中背景动画模式时渲染背景动画
          if (currentVisualizationMode === 'background') {
            renderBackgroundAnimation(dataArray);
          }
          
          animationId = requestAnimationFrame(animate);
        }
        
        animate();
      }
      
      // 渲染柱状图可视化
      function renderBarsVisualization(dataArray) {
        const bars = waveform.querySelectorAll('.bar');
        
        for (let i = 0; i < bars.length; i++) {
          const value = dataArray[i] || 0;
          const percent = value / 255;
          const height = Math.max(2, percent * 180);
          
          bars[i].style.height = height + 'px';
          
          // 卡通风格的动态颜色变化
          const hue = 240 + (percent * 120) + Math.sin(Date.now() * 0.001 + i * 0.1) * 20;
          const saturation = 70 + (percent * 30);
          const lightness = 50 + (percent * 20) + Math.cos(Date.now() * 0.002 + i * 0.05) * 10;
          
          bars[i].style.background = `linear-gradient(to top, 
            hsl(${hue}, ${saturation}%, ${lightness}%), 
            hsl(${hue + 20}, ${saturation}%, ${lightness + 10}%))`;
          
          bars[i].style.boxShadow = `0 2px 8px hsla(${hue}, ${saturation}%, ${lightness}%, 0.3),
                                     0 0 ${percent * 20}px hsla(${hue}, 100%, 70%, 0.4)`;
          
          // 添加卡通弹跳效果
          bars[i].style.transform = `scaleY(${1 + percent * 0.2}) scaleX(${1 + Math.sin(Date.now() * 0.005 + i) * 0.1})`;
        }
      }
      
      // 渲染饼图可视化
      function renderPieVisualization(dataArray) {
        if (!pieCtx) return;
        
        const canvas = pieCanvas;
        const ctx = pieCtx;
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const radius = Math.min(centerX, centerY) * 0.7;
        
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        // 计算频率段的平均值
        const segments = 12;
        const segmentSize = Math.floor(dataArray.length / segments);
        let startAngle = -Math.PI / 2;
        
        for (let i = 0; i < segments; i++) {
          let sum = 0;
          for (let j = 0; j < segmentSize; j++) {
            sum += dataArray[i * segmentSize + j] || 0;
          }
          const average = sum / segmentSize;
          const percent = average / 255;
          
          const segmentAngle = (Math.PI * 2) / segments;
          const endAngle = startAngle + segmentAngle;
          
          // 卡通风格的动态半径，确保不为负数
          const baseRadius = radius * (0.3 + percent * 0.7);
          const dynamicOffset = Math.sin(Date.now() * 0.003 + i) * 10;
          const dynamicRadius = Math.max(5, baseRadius + dynamicOffset);
          
          // 彩虹色彩
          const hue = (i / segments) * 360 + Date.now() * 0.05;
          const saturation = 70 + percent * 30;
          const lightness = 50 + percent * 30;
          
          ctx.beginPath();
          ctx.moveTo(centerX, centerY);
          ctx.arc(centerX, centerY, dynamicRadius, startAngle, endAngle);
          ctx.closePath();
          
          // 渐变填充
          const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, dynamicRadius);
          gradient.addColorStop(0, `hsla(${hue}, ${saturation}%, ${lightness + 20}%, 0.8)`);
          gradient.addColorStop(1, `hsla(${hue}, ${saturation}%, ${lightness}%, 0.6)`);
          
          ctx.fillStyle = gradient;
          ctx.fill();
          
          // 发光边框
          ctx.strokeStyle = `hsla(${hue}, 100%, 70%, 0.8)`;
          ctx.lineWidth = 2 + percent * 3;
          ctx.stroke();
          
          startAngle = endAngle;
        }
        
        // 中心装饰圆
        ctx.beginPath();
        ctx.arc(centerX, centerY, 20, 0, Math.PI * 2);
        ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
        ctx.fill();
        ctx.strokeStyle = 'rgba(102, 126, 234, 0.8)';
        ctx.lineWidth = 3;
        ctx.stroke();
      }
      
      // 渲染波形图可视化
      function renderWaveVisualization(dataArray) {
        if (!waveCtx) return;
        
        const canvas = waveCanvas;
        const ctx = waveCtx;
        const width = canvas.width;
        const height = canvas.height;
        
        ctx.clearRect(0, 0, width, height);
        
        // 绘制多层波形
        const layers = 3;
        for (let layer = 0; layer < layers; layer++) {
          ctx.beginPath();
          
          const amplitude = (height / 4) * (1 - layer * 0.2);
          const frequency = 0.02 + layer * 0.01;
          const phase = Date.now() * 0.001 * (layer + 1);
          
          for (let x = 0; x < width; x++) {
            const dataIndex = Math.floor((x / width) * dataArray.length);
            const audioValue = (dataArray[dataIndex] || 0) / 255;
            
            // 卡通风格的波形计算
            const baseY = height / 2;
            const waveY = Math.sin(x * frequency + phase) * amplitude * (0.5 + audioValue);
            const noiseY = Math.sin(x * 0.05 + phase * 2) * 10 * audioValue;
            
            const y = baseY + waveY + noiseY;
            
            if (x === 0) {
              ctx.moveTo(x, y);
            } else {
              ctx.lineTo(x, y);
            }
          }
          
          // 彩色渐变描边
          const gradient = ctx.createLinearGradient(0, 0, width, 0);
          gradient.addColorStop(0, `hsla(${240 + layer * 60}, 70%, 60%, 0.8)`);
          gradient.addColorStop(0.5, `hsla(${300 + layer * 60}, 80%, 70%, 0.9)`);
          gradient.addColorStop(1, `hsla(${360 + layer * 60}, 70%, 60%, 0.8)`);
          
          ctx.strokeStyle = gradient;
          ctx.lineWidth = 3 + layer;
          ctx.lineCap = 'round';
          ctx.lineJoin = 'round';
          ctx.stroke();
        }
      }
      
      // 初始化粒子
      function initParticles() {
        particles = [];
        for (let i = 0; i < 50; i++) {
          particles.push({
            x: Math.random() * (particlesCanvas?.width || 400),
            y: Math.random() * (particlesCanvas?.height || 200),
            vx: (Math.random() - 0.5) * 2,
            vy: (Math.random() - 0.5) * 2,
            size: Math.random() * 4 + 2,
            hue: Math.random() * 360,
            life: 1
          });
        }
      }
      
      // 渲染粒子效果可视化
      function renderParticlesVisualization(dataArray) {
        if (!particlesCtx) return;
        
        const canvas = particlesCanvas;
        const ctx = particlesCtx;
        const width = canvas.width;
        const height = canvas.height;
        
        ctx.clearRect(0, 0, width, height);
        
        // 计算音频能量
        let totalEnergy = 0;
        for (let i = 0; i < dataArray.length; i++) {
          totalEnergy += dataArray[i];
        }
        const avgEnergy = totalEnergy / dataArray.length / 255;
        
        // 更新和绘制粒子
        particles.forEach((particle, index) => {
          // 根据音频数据更新粒子
          const audioInfluence = dataArray[index % dataArray.length] / 255;
          
          particle.x += particle.vx + audioInfluence * 2;
          particle.y += particle.vy + Math.sin(Date.now() * 0.001 + index) * audioInfluence;
          
          // 边界反弹
          if (particle.x < 0 || particle.x > width) particle.vx *= -1;
          if (particle.y < 0 || particle.y > height) particle.vy *= -1;
          
          // 限制位置
          particle.x = Math.max(0, Math.min(width, particle.x));
          particle.y = Math.max(0, Math.min(height, particle.y));
          
          // 动态大小和颜色
          const dynamicSize = particle.size * (1 + audioInfluence * 2);
          const dynamicHue = (particle.hue + Date.now() * 0.1 + audioInfluence * 100) % 360;
          
          // 绘制粒子
          ctx.beginPath();
          ctx.arc(particle.x, particle.y, dynamicSize, 0, Math.PI * 2);
          
          const gradient = ctx.createRadialGradient(
            particle.x, particle.y, 0,
            particle.x, particle.y, dynamicSize
          );
          gradient.addColorStop(0, `hsla(${dynamicHue}, 80%, 70%, 0.9)`);
          gradient.addColorStop(1, `hsla(${dynamicHue}, 80%, 50%, 0.1)`);
          
          ctx.fillStyle = gradient;
          ctx.fill();
          
          // 连接线效果
          particles.forEach((otherParticle, otherIndex) => {
            if (index !== otherIndex) {
              const dx = particle.x - otherParticle.x;
              const dy = particle.y - otherParticle.y;
              const distance = Math.sqrt(dx * dx + dy * dy);
              
              if (distance < 100 && audioInfluence > 0.3) {
                ctx.beginPath();
                ctx.moveTo(particle.x, particle.y);
                ctx.lineTo(otherParticle.x, otherParticle.y);
                ctx.strokeStyle = `hsla(${dynamicHue}, 60%, 60%, ${0.3 * (1 - distance / 100) * audioInfluence})`;
                ctx.lineWidth = 1;
                ctx.stroke();
              }
            }
          });
        });
      }
      
      // 渲染圆形谱可视化
      function renderCircularVisualization(dataArray) {
        if (!circularCtx) return;
        
        const canvas = circularCanvas;
        const ctx = circularCtx;
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const maxRadius = Math.min(centerX, centerY) * 0.8;
        
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        const bars = 64;
        const angleStep = (Math.PI * 2) / bars;
        
        for (let i = 0; i < bars; i++) {
          const dataIndex = Math.floor((i / bars) * dataArray.length);
          const value = dataArray[dataIndex] || 0;
          const percent = value / 255;
          
          const angle = i * angleStep - Math.PI / 2;
          const innerRadius = maxRadius * 0.3;
          const outerRadius = innerRadius + (maxRadius - innerRadius) * percent;
          
          // 卡通风格的动态效果
          const dynamicInner = innerRadius + Math.sin(Date.now() * 0.003 + i * 0.1) * 5;
          const dynamicOuter = outerRadius + Math.cos(Date.now() * 0.002 + i * 0.05) * 10;
          
          const x1 = centerX + Math.cos(angle) * dynamicInner;
          const y1 = centerY + Math.sin(angle) * dynamicInner;
          const x2 = centerX + Math.cos(angle) * dynamicOuter;
          const y2 = centerY + Math.sin(angle) * dynamicOuter;
          
          // 彩虹色彩
          const hue = (i / bars) * 360 + Date.now() * 0.05;
          const saturation = 70 + percent * 30;
          const lightness = 50 + percent * 30;
          
          ctx.beginPath();
          ctx.moveTo(x1, y1);
          ctx.lineTo(x2, y2);
          
          // 渐变描边
          const gradient = ctx.createLinearGradient(x1, y1, x2, y2);
          gradient.addColorStop(0, `hsla(${hue}, ${saturation}%, ${lightness + 20}%, 0.6)`);
          gradient.addColorStop(1, `hsla(${hue}, ${saturation}%, ${lightness}%, 0.9)`);
          
          ctx.strokeStyle = gradient;
          ctx.lineWidth = 3 + percent * 4;
          ctx.lineCap = 'round';
          ctx.stroke();
          
          // 发光效果
          ctx.shadowColor = `hsla(${hue}, 100%, 70%, 0.5)`;
          ctx.shadowBlur = 5 + percent * 10;
          ctx.stroke();
          ctx.shadowBlur = 0;
        }
        
        // 中心装饰
        const centerRadius = maxRadius * 0.3 * 0.8;
        ctx.beginPath();
        ctx.arc(centerX, centerY, centerRadius, 0, Math.PI * 2);
        const centerGradient = ctx.createRadialGradient(
          centerX, centerY, 0,
          centerX, centerY, centerRadius
        );
        centerGradient.addColorStop(0, 'rgba(255, 255, 255, 0.9)');
        centerGradient.addColorStop(1, 'rgba(102, 126, 234, 0.3)');
        ctx.fillStyle = centerGradient;
        ctx.fill();
      }
      
      // 初始化背景粒子
      function initBackgroundParticles() {
        backgroundParticles = [];
        for (let i = 0; i < 20; i++) {
          backgroundParticles.push({
            x: Math.random() * window.innerWidth,
            y: Math.random() * window.innerHeight,
            vx: (Math.random() - 0.5) * 0.5,
            vy: (Math.random() - 0.5) * 0.5,
            size: Math.random() * 3 + 1,
            hue: Math.random() * 360,
            opacity: Math.random() * 0.3 + 0.1
          });
        }
      }
      
      // 渲染背景动画
      function renderBackgroundAnimation(dataArray) {
        if (!backgroundAnimation) return;
        
        // 计算音频能量
        let totalEnergy = 0;
        for (let i = 0; i < dataArray.length; i++) {
          totalEnergy += dataArray[i];
        }
        const avgEnergy = totalEnergy / dataArray.length / 255;
        
        // 动态背景渐变
        const hue1 = (Date.now() * 0.02 + avgEnergy * 100) % 360;
        const hue2 = (hue1 + 60) % 360;
        const opacity = 0.1 + avgEnergy * 0.2;
        
        backgroundAnimation.style.background = `
          radial-gradient(circle at 20% 20%, hsla(${hue1}, 60%, 70%, ${opacity}) 0%, transparent 50%),
          radial-gradient(circle at 80% 80%, hsla(${hue2}, 60%, 70%, ${opacity}) 0%, transparent 50%),
          radial-gradient(circle at 40% 60%, hsla(${(hue1 + hue2) / 2}, 60%, 70%, ${opacity * 0.5}) 0%, transparent 50%)
        `;
        
        // 脉冲效果
        const scale = 1 + avgEnergy * 0.1;
        backgroundAnimation.style.transform = `scale(${scale})`;
        
        // 渲染跳舞角色
        renderDancingCharacters(dataArray);
      }
      
      // 初始化跳舞角色
      function initDancingCharacters() {
        dancingCharacters = [];
        
        // 创建5个不同的卡通角色
        const characters = [
          { emoji: '🐱', name: 'cat', color: '#FF6B6B' },
          { emoji: '🐶', name: 'dog', color: '#4ECDC4' },
          { emoji: '🐰', name: 'rabbit', color: '#45B7D1' },
          { emoji: '🐸', name: 'frog', color: '#96CEB4' },
          { emoji: '🐼', name: 'panda', color: '#FFEAA7' }
        ];
        
        characters.forEach((char, index) => {
          dancingCharacters.push({
            emoji: char.emoji,
            name: char.name,
            color: char.color,
            x: 50 + index * 80, // 水平分布
            y: 150,
            baseY: 150,
            scale: 1,
            rotation: 0,
            bouncePhase: index * Math.PI / 2, // 不同的弹跳相位
            dancePhase: index * Math.PI / 3,  // 不同的舞蹈相位
            energy: 0,
            armAngle: 0,
            legAngle: 0
          });
        });
      }
      
      // 渲染跳舞角色
      function renderDancingCharacters(dataArray) {
        if (!backgroundAnimation || dancingCharacters.length === 0) return;
        
        // 计算音频能量
        let totalEnergy = 0;
        let bassEnergy = 0;
        let midEnergy = 0;
        let trebleEnergy = 0;
        
        for (let i = 0; i < dataArray.length; i++) {
          const value = dataArray[i] / 255;
          totalEnergy += value;
          
          if (i < dataArray.length * 0.3) bassEnergy += value;
          else if (i < dataArray.length * 0.7) midEnergy += value;
          else trebleEnergy += value;
        }
        
        const avgEnergy = totalEnergy / dataArray.length;
        const bassAvg = bassEnergy / (dataArray.length * 0.3);
        const midAvg = midEnergy / (dataArray.length * 0.4);
        const trebleAvg = trebleEnergy / (dataArray.length * 0.3);
        
        // 清除之前的角色
        const existingChars = backgroundAnimation.querySelectorAll('.dancing-character');
        existingChars.forEach(char => char.remove());
        
        // 渲染每个角色
        dancingCharacters.forEach((character, index) => {
          // 根据不同频段更新角色动画
          const time = Date.now() * 0.001;
          
          // 弹跳动画（低频驱动）
          const bounceIntensity = bassAvg * 30;
          character.y = character.baseY - Math.abs(Math.sin(time * 4 + character.bouncePhase)) * bounceIntensity;
          
          // 缩放动画（中频驱动）
          character.scale = 1 + midAvg * 0.5 + Math.sin(time * 6 + character.dancePhase) * 0.2;
          
          // 旋转动画（高频驱动）
          character.rotation = Math.sin(time * 3 + character.dancePhase) * trebleAvg * 20;
          
          // 手臂摆动
          character.armAngle = Math.sin(time * 8 + character.dancePhase) * 45;
          
          // 腿部动作
          character.legAngle = Math.sin(time * 6 + character.dancePhase + Math.PI) * 30;
          
          // 创建角色元素
          const charElement = document.createElement('div');
          charElement.className = 'dancing-character';
          charElement.style.cssText = `
            position: absolute;
            left: ${character.x}px;
            top: ${character.y}px;
            font-size: ${24 * character.scale}px;
            transform: rotate(${character.rotation}deg);
            transition: all 0.1s ease-out;
            z-index: 10;
            user-select: none;
            pointer-events: none;
            filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3));
            animation: characterGlow 0.5s ease-in-out infinite alternate;
          `;
          
          // 添加发光效果
          const glowIntensity = avgEnergy;
          charElement.style.textShadow = `
            0 0 ${5 + glowIntensity * 10}px ${character.color},
            0 0 ${10 + glowIntensity * 20}px ${character.color},
            0 0 ${15 + glowIntensity * 30}px ${character.color}
          `;
          
          charElement.textContent = character.emoji;
          
          // 添加角色特定的动画类
           charElement.style.animation = `characterGlow 0.5s ease-in-out infinite alternate, characterBounce ${1 + bassAvg}s ease-in-out infinite`;
           
           // 添加手臂和腿部的动态变换
           charElement.setAttribute('data-arm-angle', character.armAngle);
           charElement.setAttribute('data-leg-angle', character.legAngle);
           
           backgroundAnimation.appendChild(charElement);
           
           // 更新伪元素的变换（通过CSS变量）
           charElement.style.setProperty('--arm-rotation', `${character.armAngle}deg`);
           charElement.style.setProperty('--leg-rotation', `${character.legAngle}deg`);
        });
      }

      // 停止可视化
      function stopVisualization() {
        if (animationId) {
          cancelAnimationFrame(animationId);
          animationId = null;
        }
        
        // 根据当前模式执行相应的停止动画
        switch(currentVisualizationMode) {
          case 'bars':
            animateToZero();
            break;
          case 'pie':
            if (pieCtx) pieCtx.clearRect(0, 0, pieCanvas.width, pieCanvas.height);
            break;
          case 'wave':
            if (waveCtx) waveCtx.clearRect(0, 0, waveCanvas.width, waveCanvas.height);
            break;
          case 'particles':
            if (particlesCtx) particlesCtx.clearRect(0, 0, particlesCanvas.width, particlesCanvas.height);
            break;
          case 'circular':
            if (circularCtx) circularCtx.clearRect(0, 0, circularCanvas.width, circularCanvas.height);
            break;
          case 'background':
            if (backgroundAnimation) {
              backgroundAnimation.style.background = '';
              backgroundAnimation.style.transform = '';
              backgroundAnimation.innerHTML = '';
            }
            break;
        }
      }
      
      /**
       * 缓慢归零动画效果
       * 当播放暂停或停止时，频率条平滑降低到最小高度
       * 使用ease-out缓动函数和颜色渐变效果
       */
      function animateToZero() {
        const bars = waveform.querySelectorAll('.bar');
        const duration = 1500; // 1.5秒动画时间
        const startTime = performance.now();
        
        // 记录每个条的初始高度作为动画起点
        const initialHeights = Array.from(bars).map(bar => {
          const currentHeight = parseFloat(bar.style.height) || 2;
          return Math.max(currentHeight, 2);
        });
        
        function animate(currentTime) {
          const elapsed = currentTime - startTime;
          const progress = Math.min(elapsed / duration, 1);
          
          // 使用三次方ease-out缓动函数，开始快速后逐渐减慢
          const easeOut = 1 - Math.pow(1 - progress, 3);
          
          bars.forEach((bar, index) => {
            const initialHeight = initialHeights[index];
            const targetHeight = 2; // 最小高度
            const currentHeight = initialHeight - (initialHeight - targetHeight) * easeOut;
            
            bar.style.height = currentHeight + 'px';
            
            // 颜色透明度也逐渐降低，营造淡出效果
            const opacity = 1 - easeOut * 0.7; // 保留30%的不透明度
            const hue = 240; // 蓝色基调
            const saturation = 70 * opacity;
            const lightness = 50 + (1 - opacity) * 20;
            
            // 应用渐变背景和透明度
            bar.style.background = `linear-gradient(to top, 
              hsla(${hue}, ${saturation}%, ${lightness}%, ${opacity}), 
              hsla(${hue + 20}, ${saturation}%, ${lightness + 10}%, ${opacity * 0.8}))`;
            
            // 阴影效果也同步减弱
            bar.style.boxShadow = `0 2px 8px hsla(${hue}, ${saturation}%, ${lightness}%, ${opacity * 0.3})`;
          });
          
          if (progress < 1) {
            requestAnimationFrame(animate);
          } else {
            // 动画结束，恢复默认样式
            bars.forEach(bar => {
              bar.style.height = '2px';
              bar.style.background = 'var(--accent-primary)';
              bar.style.boxShadow = '0 2px 8px rgba(102, 126, 234, 0.3)';
            });
          }
        }
        
        requestAnimationFrame(animate);
      }

      // 更新状态
      function updateStatus(message, status = 'playing') {
        statusText.textContent = message;
        statusDot.className = 'status-dot';
        statusDot.classList.add(status);
      }

      // 播放媒体
      function playMedia(index) {
        if (index < 0 || index >= playlist.length) return;
        
        const media = playlist[index];
        currentIndex = index;
        
        // 停止当前播放
        if (currentMedia) {
          currentMedia.pause();
          currentMedia.currentTime = 0;
        }
        
        // 隐藏所有播放器
        videoPlayer.style.display = 'none';
        audioPlayer.style.display = 'none';
        placeholderText.style.display = 'none';
        
        // 根据文件类型选择播放器
        if (media.type.startsWith('video/')) {
          currentMedia = videoPlayer;
          videoPlayer.style.display = 'block';
        } else {
          currentMedia = audioPlayer;
          audioPlayer.style.display = 'block';
        }
        
        currentMedia.src = media.url;
        
        // 初始化音频可视化
        initAudioContext(currentMedia);
        
        // 播放媒体
        currentMedia.play().then(() => {
          isPlaying = true;
          updateStatus(`正在播放: ${media.name}`, 'playing');
          updatePlaylistDisplay();
        }).catch(error => {
          console.error('播放失败:', error);
          updateStatus('播放失败', 'error');
        });
        
        // 添加事件监听
        currentMedia.onended = () => {
          isPlaying = false;
          stopVisualization();
          updateStatus('播放结束', 'paused');
          
          // 自动播放下一首
          if (currentIndex < playlist.length - 1) {
            setTimeout(() => playMedia(currentIndex + 1), 1000);
          }
        };
        
        currentMedia.onpause = () => {
          isPlaying = false;
          stopVisualization(); // 暂停时也触发归零动画
          updateStatus('已暂停', 'paused');
        };
        
        currentMedia.onplay = () => {
          isPlaying = true;
          startVisualization(); // 恢复播放时重新启动可视化
          updateStatus(`正在播放: ${media.name}`, 'playing');
        };
      }

      // 添加文件到播放列表
      function addToPlaylist(files) {
        Array.from(files).forEach(file => {
          const url = URL.createObjectURL(file);
          const media = {
            name: file.name,
            url: url,
            type: file.type,
            size: file.size
          };
          
          playlist.push(media);
        });
        
        updatePlaylistDisplay();
        
        // 如果是第一个文件，自动播放
        if (playlist.length === files.length) {
          playMedia(0);
        }
      }

      // 更新播放列表显示
      function updatePlaylistDisplay() {
        playlistEl.innerHTML = '';
        
        if (playlist.length === 0) {
          playlistEl.innerHTML = '<li style="text-align: center; color: var(--text-muted); font-style: italic;">暂无媒体文件</li>';
          return;
        }
        
        playlist.forEach((media, index) => {
          const li = document.createElement('li');
          li.dataset.index = index;
          if (index === currentIndex) li.classList.add('active');
          
          const isVideo = media.type.startsWith('video/');
          const formatSize = (bytes) => {
            const sizes = ['B', 'KB', 'MB', 'GB'];
            if (bytes === 0) return '0 B';
            const i = Math.floor(Math.log(bytes) / Math.log(1024));
            return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
          };
          
          li.innerHTML = `
            <div class="media-info">
              <div class="title">${media.name}</div>
              <div class="type">${formatSize(media.size)} • ${isVideo ? '视频' : '音频'}</div>
            </div>
            <span class="format-tag ${isVideo ? 'video' : 'audio'}">
              ${isVideo ? '📹' : '🎵'}
            </span>
          `;
          
          li.addEventListener('click', () => playMedia(index));
          playlistEl.appendChild(li);
        });
      }

      // 事件监听器
      fileInput.addEventListener('change', (e) => {
        if (e.target.files.length > 0) {
          addToPlaylist(e.target.files);
          e.target.value = ''; // 清空input
        }
      });

      playBtn.addEventListener('click', () => {
        if (currentMedia) {
          currentMedia.play();
        } else if (playlist.length > 0) {
          playMedia(0);
        } else {
          updateStatus('请先选择媒体文件', 'error');
        }
      });

      pauseBtn.addEventListener('click', () => {
        if (currentMedia) {
          currentMedia.pause();
        }
      });

      stopBtn.addEventListener('click', () => {
        if (currentMedia) {
          currentMedia.pause();
          currentMedia.currentTime = 0;
          isPlaying = false;
          stopVisualization();
          updateStatus('已停止', 'paused');
        }
      });

      clearPlaylistBtn.addEventListener('click', () => {
        if (confirm('确定要清空播放列表吗？')) {
          // 释放所有URL对象
          playlist.forEach(media => {
            if (media.url.startsWith('blob:')) {
              URL.revokeObjectURL(media.url);
            }
          });
          
          playlist = [];
          currentIndex = -1;
          
          if (currentMedia) {
            currentMedia.pause();
            currentMedia.src = '';
            currentMedia = null;
          }
          
          isPlaying = false;
          stopVisualization();
          
          // 隐藏播放器，显示占位符
          videoPlayer.style.display = 'none';
          audioPlayer.style.display = 'none';
          placeholderText.style.display = 'flex';
          
          updatePlaylistDisplay();
          updateStatus('播放列表已清空', 'paused');
          
          // 重置可视化器显示
          waveform.innerHTML = `
            <div style="display: flex; align-items: center; justify-content: center; width: 100%; color: var(--text-muted); font-size: 1rem;">
              🎶 音频可视化将在播放时显示
            </div>
          `;
          
          // 清空所有Canvas
          if (pieCtx) pieCtx.clearRect(0, 0, pieCanvas.width, pieCanvas.height);
          if (waveCtx) waveCtx.clearRect(0, 0, waveCanvas.width, waveCanvas.height);
          if (particlesCtx) particlesCtx.clearRect(0, 0, particlesCanvas.width, particlesCanvas.height);
          if (circularCtx) circularCtx.clearRect(0, 0, circularCanvas.width, circularCanvas.height);
          
          // 重置背景动画
          if (backgroundAnimation) {
            backgroundAnimation.style.background = '';
            backgroundAnimation.style.transform = '';
          }
        }
      });

      // 拖放支持
      document.addEventListener('dragover', (e) => {
        e.preventDefault();
      });

      document.addEventListener('drop', (e) => {
        e.preventDefault();
        const files = e.dataTransfer.files;
        if (files.length > 0) {
          addToPlaylist(files);
        }
      });

      // 键盘快捷键
      document.addEventListener('keydown', (e) => {
        if (e.target.tagName === 'INPUT') return;
        
        switch(e.code) {
          case 'Space':
            e.preventDefault();
            if (currentMedia) {
              if (currentMedia.paused) {
                currentMedia.play();
              } else {
                currentMedia.pause();
              }
            }
            break;
          case 'ArrowLeft':
            if (currentMedia) {
              currentMedia.currentTime = Math.max(0, currentMedia.currentTime - 10);
            }
            break;
          case 'ArrowRight':
            if (currentMedia) {
              currentMedia.currentTime = Math.min(currentMedia.duration, currentMedia.currentTime + 10);
            }
            break;
          case 'ArrowUp':
            e.preventDefault();
            if (currentIndex > 0) {
              playMedia(currentIndex - 1);
            }
            break;
          case 'ArrowDown':
            e.preventDefault();
            if (currentIndex < playlist.length - 1) {
              playMedia(currentIndex + 1);
            }
            break;
        }
      });

      // 可视化模式切换事件监听
      controlCards.forEach(card => {
        card.addEventListener('click', () => {
          const mode = card.dataset.mode;
          switchVisualizationMode(mode);
        });
      });
      
      // 初始化
      initCanvases();
      updateStatus('就绪 - 请选择媒体文件开始播放');
      updatePlaylistDisplay();
      
      // 窗口大小改变时重新初始化Canvas
      window.addEventListener('resize', () => {
        setTimeout(initCanvases, 100);
      });

      // 页面卸载时清理资源
      window.addEventListener('beforeunload', () => {
        if (audioContext) {
          audioContext.close();
        }
        if (animationId) {
          cancelAnimationFrame(animationId);
        }
        playlist.forEach(media => {
          if (media.url.startsWith('blob:')) {
            URL.revokeObjectURL(media.url);
          }
        });
      });
    </script>
  </body>
</html>